//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler execution subsystem
// FILE:            xgen.h - all stuff related object code generation and jit
// AUTHOR:          Vladimir Gumenuk
// DATE:            7-Oct-2014
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#pragma once

#include "xbyak.h"
#include "xgendefs.h"

//////////////////////////////////////////////////////////////////////////
// This base class is a helper to generate object code

class XGenerator : public Xbyak::CodeGenerator
{
public:
    XGenerator( void *pMemory, size_t dwSize );
    virtual ~XGenerator();

    void push_imm_byte( BYTE val );           // push FF
    void push_imm_word( WORD val );           // push FFFF
    void push_imm_dword( DWORD val );         // push FFFFFFFF
    void push_imm_qword( QWORD val );         // push FFFFFFFFFFFFFFFF
    void push_GPR( Register64 rg );           // push rax
    
    void pop_GPR( Register64 rg );            // pop rax
    
    void mov_GPR_GPR( Register64 regDst, Register64 regSrc );       // mov rax, rdx
    void mov_GPR_imm_byte( Register64 regDst, BYTE val );           // mov rax, FF
    void mov_GPR_imm_word( Register64 regDst, WORD val );           // mov rax, FFFF
    void mov_GPR_imm_dword( Register64 regDst, DWORD val );         // mov rax, FFFFFFFF
    void mov_GPR_imm_qword( Register64 regDst, QWORD val );         // mov rax, FFFFFFFFFFFFFFFF

    void mov_byte_ptr_MEM_GPR( QWORD qwAddrDst, Register64 rg );        // mov byte ptr Addr, rax
    void mov_word_ptr_MEM_GPR( QWORD qwAddrDst, Register64 rg );        // mov word ptr Addr, rax
    void mov_dword_ptr_MEM_GPR( QWORD qwAddrDst, Register64 rg );       // mov dword ptr Addr, rax
    void mov_qword_ptr_MEM_GPR( QWORD qwAddrDst, Register64 rg );       // mov qword ptr Addr, rax

    void mov_byte_ptr_MEM_Base_disp_GPR(  QWORD qwAddrDst, DWORD dwDisp, Register64 rg ); // mov byte ptr Addr, [rg+disp]
    void mov_word_ptr_MEM_Base_disp_GPR( QWORD qwAddrDst, DWORD dwDisp, Register64 rg ); // mov word ptr Addr, [rg+disp]
    void mov_dword_ptr_MEM_Base_disp_GPR( QWORD qwAddrDst, DWORD dwDisp, Register64 rg ); // mov dword ptr Addr, [rg+disp]
    void mov_qword_ptr_MEM_Base_disp_GPR( QWORD qwAddrDst, DWORD dwDisp, Register64 rg ); // mov qword ptr Addr, [rg+disp]

    void mov_GPR_byte_ptr_Base_disp(  Register64 rgDst, Register64 rgBase, DWORD dwDisp ); // mov rgDst, byte ptr [rgSrc+disp]
    void mov_GPR_word_ptr_Base_disp(  Register64 rgDst, Register64 rgBase, DWORD dwDisp ); // mov rgDst, word ptr [rgSrc+disp]
    void mov_GPR_dword_ptr_Base_disp( Register64 rgDst, Register64 rgBase, DWORD dwDisp ); // mov rgDst, dword ptr [rgSrc+disp]
    void mov_GPR_qword_ptr_Base_disp( Register64 rgDst, Register64 rgBase, DWORD dwDisp ); // mov rgDst, qword ptr [rgSrc+disp]

    void mov_byte_ptr_Base_disp_GPR(  Register64 regBase, DWORD dwDisp, Register64 regMov ); // mov byte ptr [rbp+8], al
    void mov_word_ptr_Base_disp_GPR(  Register64 regBase, DWORD dwDisp, Register64 regMov ); // mov word ptr [rbp+8], ax
    void mov_dword_ptr_Base_disp_GPR( Register64 regBase, DWORD dwDisp, Register64 regMov ); // mov dword ptr [rbp+8], eax
    void mov_qword_ptr_Base_disp_GPR( Register64 regBase, DWORD dwDisp, Register64 regMov ); // mov qword ptr [rbp+8], rax

    void deref_GPR_byte_ptr( Register64 rg );                              // mov rax, byte  ptr[rax]
    void deref_GPR_word_ptr( Register64 rg );                              // mov rax, word  ptr[rax]
    void deref_GPR_dword_ptr( Register64 rg );                             // mov rax, dword ptr[rax]
    void deref_GPR_qword_ptr( Register64 rg );                             // mov rax, qword ptr[rax]
    void deref_GPR_qword_ptr_GPR( Register64 regDst, Register64 regSrc );  // mov rax, qword ptr[rdx]
    void ret_Drop( int iNumBytes );                                        // ret 0

    void sub_GPR_imm_byte( Register64 rg, BYTE val );  // sub rax, 0xFF
    void add_GPR_imm_byte( Register64 rg, BYTE val );  // add rax, 0xFF

    void declare_label( int iIdx );
    void goto_label( int iIdx );

    void cmp_byte_GPR_GPR(  Register64 rg1, Register64 rg2 );   // cmp al, bl
    void cmp_word_GPR_GPR(  Register64 rg1, Register64 rg2 );   // cmp ax, bx
    void cmp_dword_GPR_GPR( Register64 rg1, Register64 rg2 );   // cmp eax, ebx
    void cmp_qword_GPR_GPR( Register64 rg1, Register64 rg2 );   // cmp rax, rbx

    void cmp_GPR_byte_ptr_Base_disp(  Register64 rg, Register64 rgBase, DWORD dwDisp );   // cmp al, byte ptr[rg+disp]
    void cmp_GPR_word_ptr_Base_disp(  Register64 rg, Register64 rgBase, DWORD dwDisp );   // cmp ax, word ptr[rg+disp]
    void cmp_GPR_dword_ptr_Base_disp( Register64 rg, Register64 rgBase, DWORD dwDisp );   // cmp eax, dword ptr[rg+disp]
    void cmp_GPR_qword_ptr_Base_disp( Register64 rg, Register64 rgBase, DWORD dwDisp );   // cmp rax, qword ptr[rg+disp]

    void cmp_byte_ptr_Base_disp_GPR(  Register64 rgBase, DWORD dwDisp, Register64 rg );   // cmp byte ptr[rg+disp], al
    void cmp_word_ptr_Base_disp_GPR(  Register64 rgBase, DWORD dwDisp, Register64 rg );   // cmp word ptr[rg+disp], ax
    void cmp_dword_ptr_Base_disp_GPR( Register64 rgBase, DWORD dwDisp, Register64 rg );   // cmp dword ptr[rg+disp], eax
    void cmp_qword_ptr_Base_disp_GPR( Register64 rgBase, DWORD dwDisp, Register64 rg );   // cmp qword ptr[rg+disp], rax

private:
    Xbyak::Reg findRegFromIdx( Register64 rg, int iSize = 64 );

};
